﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Net;
using System.Web;
using Sgml;

namespace OpenGraphNET.Lib
{
    public class OpenGraphLib
    {
        /// <summary>
        /// Populate an OpenGraphObject based on information found at a particular URL
        /// Currently uses the SGML parser to convert 
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static OpenGraphObject PopulateOpenGraphObject(string url)
        {
            //Create new open graph object
            OpenGraphObject ogObject = new OpenGraphObject();

            //Download the source and convert it to XML
            XmlDocument xd = ConvertPageToXml(url);
            string xpath = @"//meta[@property]";

            //Loop through all meta tags that contain a property attribute
            foreach (XmlNode xmlnode in xd.SelectNodes(xpath))
            {
                //limit to only OpenGraph items
                if (xmlnode.Attributes["property"].Value.Contains("og:"))
                {
                    string key = RemoveOpenGraphPrefix(xmlnode.Attributes["property"].Value);
                    string value = xmlnode.Attributes["content"].Value;

                    if (key.ToLower() == "title")
                        ogObject.title = value;
                    else if (key.ToLower() == "type")
                        ogObject.type = value;
                    else if (key.ToLower() == "image")
                        ogObject.url = value;
                    else if (key.ToLower() == "url")
                        ogObject.image = value;
                    else if (key.ToLower() == "site_name")
                        ogObject.site_name = value;
                    else if (key.ToLower() == "description")
                        ogObject.description = value;
                    else
                    {
                        //add to dictionary to allow for extended properties
                        ogObject.extendedProperties.Add(key.ToLower(), value);
                    }

                    //add to dictionary to allow for all properties
                    ogObject.allProperties.Add(key.ToLower(), value);
                }
            }

            //return the dictionary object after it has been populated
            return ogObject;
        }

        /// <summary>
        /// Create an HTML block to be put inside the head tags.
        /// </summary>
        /// <param name="ogObject"></param>
        /// <param name="checkRequired"></param>
        /// <returns></returns>
        public static string CreateOpenGraphHtml(OpenGraphObject ogObject, bool checkRequired)
        {
            string html = "";

            //if true, check that required properties appear
            if (checkRequired)
            {
                if (string.IsNullOrEmpty(ogObject.title))
                    return "Error: Required title property is missing";  //todo: replace with exception
                if (string.IsNullOrEmpty(ogObject.type))
                    return "Error: Required type property is missing";
                if (string.IsNullOrEmpty(ogObject.image))
                    return "Error: Required image property is missing";
                if (string.IsNullOrEmpty(ogObject.url))
                    return "Error: Required url property is missing";
            }

            //create required html here
            if (!string.IsNullOrEmpty(ogObject.title))
                html += "<meta property=\"og:title\" content=\"" + ogObject.title + "\" />" + Environment.NewLine;
            if (!string.IsNullOrEmpty(ogObject.type))
                html += "<meta property=\"og:type\" content=\"" + ogObject.type + "\" />" + Environment.NewLine;
            if (!string.IsNullOrEmpty(ogObject.image))
                html += "<meta property=\"og:image\" content=\"" + ogObject.image + "\" />" + Environment.NewLine;
            if (!string.IsNullOrEmpty(ogObject.title))
                html += "<meta property=\"og:url\" content=\"" + ogObject.url + "\" />" + Environment.NewLine;
            if (!string.IsNullOrEmpty(ogObject.site_name))
                html += "<meta property=\"og:site_name\" content=\"" + ogObject.site_name + "\" />" + Environment.NewLine;
            if (!string.IsNullOrEmpty(ogObject.description))
                html += "<meta property=\"og:description\" content=\"" + ogObject.description + "\" />" + Environment.NewLine;

            //create meta html tags here
            foreach (KeyValuePair<string, string> property in ogObject.extendedProperties)
            {
                html += "<meta property=\"og:" + property.Key + "\" content=\"" + property.Value + "\" />" + Environment.NewLine;
            }

            //Create meta HTML here
            return html;

        }

        /// <summary>
        /// Retrieve the most current schema from the OpenGraph Protocol website. 
        /// </summary>
        /// <returns></returns>
        public static string GetOpenGraphSchema()
        {
            string responseData = "";
            string schemaUrl = "http://opengraphprotocol.org/schema/";
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(schemaUrl);
            webRequest.Method = "GET";
            webRequest.Accept = "application/rdf+xml";

            StreamReader responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
            responseData = responseReader.ReadToEnd();
            responseReader.Close();
            webRequest.GetResponse().Close();

            return responseData;
        }

        /// <summary>
        /// Read in the HTML source and convert it to readable XML
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private static XmlDocument ConvertPageToXml(string url)
        {
            XmlDocument xd = new XmlDocument();
            Sgml.SgmlReader sg = new Sgml.SgmlReader();
            sg.DocType = "html";
            sg.Href = url;
            while (sg.Read())
            {
                xd.Load(sg);
            }

            return xd;
        }

        /// <summary>
        /// Pass HTML source and convert it to readable XML
        /// </summary>
        /// <param name="sourceHtml"></param>
        /// <returns></returns>
        private static XmlDocument ConvertSourceHtmlToXml(string sourceHtml)
        {
            XmlDocument xd = new XmlDocument();
            Sgml.SgmlReader sg = new Sgml.SgmlReader();
            sg.DocType = "html";
            sg.InputStream = new System.IO.StringReader(sourceHtml);
            while (sg.Read())
            {
                xd.Load(sg);
            }

            return xd;
        }

        /// <summary>
        /// Helper function to remove the "og:" prefix
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static string RemoveOpenGraphPrefix(string str)
        {
            return str.Replace("og:", "");
        }
    }
}
